
var Hero = new Class({
    Extends: DynaObject,
    initialize: function(type){
        if($defined(type))
            this.parent(type);
        else
            this.parent(GAMEUNITTYPE.HERO);
        this.currentDirection=null;
        this.sense=0;
        this.cuanta=2;
        //these should be the same as in the css file : div.hero
        this.width=game.standardWidth;
        this.height=game.standardHeight;
        this.hitWorldBoundary=false;
        this.hitTheWall=false;
        this.bombExplosionLength=1;
        this.numberOfBombs=1;
        this.currentSpriteFrame = {
            x: 0 ,
            y: 0
        };
        this.spriteAnimationSpeed = 5;
        this.spriteAnimationIndex = 0;
        this.score = 0;
        this.canFlyOverFakeWalls = false;
        this.life=1;
    },
    setExplosionLength: function(explosionLength){
        this.bombExplosionLength = explosionLength;
    },
    processKeyPressedInput: function(keyCode){
        if(keyCode==39){
            this.currentDirection='left';
            this.sense=1;
            this.spriteY = 50;
        }
        if(keyCode==37){
            this.currentDirection='left';
            this.sense=-1;
            this.spriteY = 100;
        }
        if(keyCode==40){
            this.currentDirection='top';
            this.sense=1;
            this.spriteY = 200;
        }
        if(keyCode==38){
            this.currentDirection='top';
            this.sense=-1;
            this.spriteY = 150;
        }
    },
    processKeyUpInput: function(keyCode){
        this.sense=0;
        this.spriteY = 1;
        this.updateHeroSprite();
    },
    processKeyDownInput: function(keyCode){
        this.processKeyPressedInput(keyCode);
    },
    launchBomb: function(){
        if(this.numberOfBombs>0){
            this.bombLaunched=true;
            this.numberOfBombs--;
            var bomb=new Bomb(this.x,this.y,this);
            bomb.setExplosionLength(this.bombExplosionLength);
        }
    },
    returnBomb: function(){
        this.bombLaunched=false;
        this.numberOfBombs++;
    },
    setNumberOfBombs: function(noBombs){
        this.numberOfBombs=noBombs;
    },
    updateHeroSprite: function(){
        if(headless)
            return;
        if(this.spriteAnimationIndex>=this.spriteAnimationSpeed){
            this.spriteAnimationIndex = 0;
        } else {
            this.spriteAnimationIndex++;
            return;
        }
        if(this.currentSpriteFrame.y!=this.spriteY){
            this.currentSpriteFrame.y=this.spriteY;
            this.spriteX = game.standardWidth;
        }
        else {
            this.spriteX += game.standardWidth;
            if(this.spriteX>=250)
                this.spriteX = game.standardWidth;
            this.currentSpriteFrame.x = this.spriteX;
        }
        //this.HTMLIncarnation.setStyle('background-position',this.spriteX+'px '+this.spriteY+'px');
        // the above line is replaced with the one below for performance reasons
        this.HTMLIncarnation.style.backgroundPosition=this.spriteX+'px '+this.spriteY+'px';
    },
    checkIdleStatus: function(){
        if(this.sense==0)
            return;
    },
    moveAlongDirection: function(){
        this.checkIdleStatus();
        if(headless){
            java.lang.System.out.println("moveAlongDirection "+this.currentDirection+"-"+this.sense+" :x="+this.x+" y="+this.y);
            Packages.ro.jlin.web.dyna.JSToJavaCaller.callAction("move","param2");
        }
        var currentPosition=0;
        var newPosition=0;
        if(this.currentDirection=='left'){
            currentPosition = this.x;
            newPosition = currentPosition+(this.sense*this.cuanta);
            if(this!=game.hero){
                var deltaX=0;
                if(this.serverX!=-1)
                    deltaX=Math.abs(newPosition-this.serverX);
                if(deltaX>this.cuanta){
                    newPosition=this.serverX;
                    this.serverX=-1;
                    if(this.y!=this.serverY){
                        //if(Browser.Engine.gecko)
                        //                console.log('y readjusted: thisy='+this.y+' will be changed to: this.serverY='+this.serverY);
                        this.y=this.serverY;
                        if(!headless){
                            //this.HTMLIncarnation.setStyle('top',this.y);
                            this.HTMLIncarnation.style.top=this.y+'px';
                        }
                    }
                }
                var deltaY=0;
                if(this.serverY!=-1)
                    deltaY=Math.abs(this.y-this.serverY);
                if(deltaY>this.cuanta){
                    //if(Browser.Engine.gecko)
                    //                   console.log('y readjusted: thisy='+this.y+' will be changed to: this.serverY='+this.serverY);
                    this.y=this.serverY;
                    if(!headless){
                        //this.HTMLIncarnation.setStyle('top',this.y);
                        this.HTMLIncarnation.style.top=this.y+'px';
                    }
                }
            }
            if((newPosition<0 && this.sense<0) || (this.sense>0 && newPosition>game.worldWidth-game.standardWidth)){
                this.hitWorldBoundary=true;
                return;
            }
        }
        if(this.currentDirection=='top'){
            currentPosition = this.y;
            newPosition = currentPosition+(this.sense*this.cuanta);
            if(this!=game.hero){
                var deltaY=0;
                if(this.serverY!=-1)
                    deltaY=Math.abs(newPosition-this.serverY);
                if(deltaY>this.cuanta){
                    newPosition=this.serverY;
                    this.serverY=-1;
                    if(this.x!=this.serverX){
                        // if(Browser.Engine.gecko)
                        //              console.log('x readjusted: thisx='+this.x+' will be changed to: this.serverX='+this.serverX);
                        this.x=this.serverX;
                        if(!headless){
                            //this.HTMLIncarnation.setStyle('left',this.x);
                            this.HTMLIncarnation.style.left=this.x+'px';
                        }
                    }
                }
                var deltaX=0;
                if(this.serverX!=-1)
                    deltaX=Math.abs(this.x-this.serverX);
                if(deltaX>this.cuanta){
                    //if(Browser.Engine.gecko)
                    //                  console.log('x readjusted: thisx='+this.x+' will be changed to: this.serverX='+this.serverX);
                    this.x=this.serverX;
                    if(!headless){
                        //this.HTMLIncarnation.setStyle('left',this.x);
                        this.HTMLIncarnation.style.left=this.x+'px';
                    }
                }
            }
            if((this.sense<0 && newPosition<0) || (this.sense>0 && newPosition>game.worldHeight-game.standardHeight)){
                this.hitWorldBoundary=true;
                return;
            }
        }
            
        var repositionedX=this.x;
        var repositionedY=this.y;
            
        //// this is when , for example, you are going down and you stop to turn the direction
        //// but you do not stop right in the spot where your coordinate allow you not to hit a wall
        //// so if you donot hit it in the middle , this code below adjust your coordinate
        //// so you don't hit it.
        if(this.currentDirection =='left'){
            repositionedY=util.rePositionCoordinate(this.y,game.standardHeight);
            if(repositionedY!=this.y){
                this.y=repositionedY;
                if(!headless){
                    //this.HTMLIncarnation.setStyle('top',this.y);
                    this.HTMLIncarnation.style.top=this.y+'px';
                }
            }
        }
        if(this.currentDirection =='top'){
            repositionedX=util.rePositionCoordinate(this.x,game.standardWidth);
            if(repositionedX!=this.x){
                this.x=repositionedX;
                if(!headless){
                    //this.HTMLIncarnation.setStyle('left',this.x);
                    this.HTMLIncarnation.style.left=this.x+'px';
                }
            }
        }
        if(!this.canFlyOverFakeWalls)
            this.hitTheWall=checkForCollisionWithWalls(this,(this.currentDirection=='left')?newPosition:repositionedX,(this.currentDirection=='top')?newPosition:repositionedY,this.currentDirection);
        else
            this.hitTheWall=false;
        if(!this.hitTheWall){
            // the hero could have hit the EXIT , and now it is reborn in another level
            if(this.reborn){
                this.reborn=false;
                return;
            }
            if(this.currentDirection=='left'){
                this.x=newPosition;
                if(!headless){
                    //this.HTMLIncarnation.setStyle(this.currentDirection,newPosition);
                    this.HTMLIncarnation.style.left=newPosition+'px';
                }
            }
            if(this.currentDirection=='top'){
                this.y=newPosition;
                if(!headless){
                    //this.HTMLIncarnation.setStyle(this.currentDirection,newPosition);
                    this.HTMLIncarnation.style.top=newPosition+'px';
                }
            }
        //this.HTMLIncarnation.setStyle(this.currentDirection,newPosition);
        } else {
            if(this.currentDirection=='left'){
                ///////// this is because when you are 1 pixel close to the wall , and try to touch it
                ///////// the collision detection method doesn't allow you to get any closer
                //////// so we are here because we hit the wall [else from !this.hitTheWall] and direction = left
                //////// and x is 1-2-3... pixels close to the wall
                var wallposition = this.x%game.standardWidth;
                if(wallposition != 0){
                    if(wallposition < game.standardWidth/2)
                        this.x-=wallposition;
                    else
                        this.x+=game.standardWidth-wallposition;
                    if(!headless){
                        //this.HTMLIncarnation.setStyle('left',this.x);
                        this.HTMLIncarnation.style.left=this.x+'px';
                    }
                }
            ////////// end adjusting from 1pixelCloseToWall issue
            }
            if(this.currentDirection=='top'){
                var wallposition = this.y%game.standardHeight;
                if(wallposition!=0){
                    if(wallposition < game.standardHeight/2)
                        this.y-=wallposition;
                    else
                        this.y+=game.standardHeight-wallposition;
                    if(!headless){
                        //this.HTMLIncarnation.setStyle('top',this.y);
                        this.HTMLIncarnation.style.top=this.y+'px';
                    }
                }
            }
        }
        if(this.x<0)
            this.x=0;
        if(this.y<0)
            this.y=0;
        this.updateHeroSprite();
        var newZone=util.getZoneAtPoint(this.x,this.y);
        if(newZone!=this.myZone){
            if(this.canFlyOverFakeWalls){
                newZone.addElement(this);
                this.myZone.removeElement(this);
                this.myZone=newZone;
            } else {
                if(newZone.isWalkable()){
                    newZone.addElement(this);
                    this.myZone.removeElement(this);
                    this.myZone=newZone;
                } else {
                    if((newZone.hasType(GAMEUNITTYPE.WALL) || newZone.hasType(GAMEUNITTYPE.FAKEWALL)) && game.debug==0 && !this.canFlyOverFakeWalls){
                        debugger;
                    //alert(this.type+' entered into a wall');
                    }
                }
            }
        }
    },
    assimilateGoody: function(zone){
        var elements = zone.getElements();
        var goody = null;
        for(var i=0;i<elements.length;i++){
            if(elements[i].type==GAMEUNITTYPE.GOODY){
                goody=elements[i];
                break;
            }
        }
        if(goody.subtype==GOODYSUBTYPE.EXIT){
            if(game.heroes.length==0){
                this.reborn=true;
                goody.terminate();
                generateNextLevel();
            }
        } else {
            if(goody.subtype==GOODYSUBTYPE.LIFE){
                this.life++;
            }
            if(goody.subtype==GOODYSUBTYPE.SPEED){
                this.cuanta++;
            }
            if(goody.subtype==GOODYSUBTYPE.BOMB){
                this.numberOfBombs++;
            }
            // more to be implemented here
            goody.terminate();
        }
    },
    terminate: function(){
        this.life--;
        if(this.life>0)
            return;
        this.parent();
        this.scream();
        this.die();
    },
    die: function(){
        var bombExplosionLength = this.bombExplosionLength;
        var numberOfBombs = this.numberOfBombs;
        var speed = this.cuanta;
        if($defined(this.bombLaunched) && this.bombLaunched)
            numberOfBombs++;
        if(this==game.hero){
            if($defined($('score')))
                $('score').set('text','0');
            this.score=0;
            game.hero=null;
            restartLevel(speed,bombExplosionLength,numberOfBombs);
        }
    },
    addPointsToScore: function(points){
        this.score += points;
        $('score').set('text',this.score);
    },
    scream: function(){
        var soundSuffix=1+Math.round(Math.random()*3);
        game.sound.playSound('scream'+soundSuffix);
    }
});
